Skip to main content

CSRF 攻击

CSRF 攻击:原理、危害与防御方案(深度解析)

一、CSRF 攻击的本质

CSRF(Cross-Site Request Forgery)跨站请求伪造,指攻击者诱导用户在已登录的状态下,无意中向目标网站发送恶意请求,利用用户的身份执行非自愿操作(如转账、修改密码等)。
核心原理:利用浏览器自动携带 cookie 等身份凭证的机制,结合用户对恶意网站的信任。

二、攻击流程与典型场景

攻击三要素
  1. 用户已登录目标网站并保持会话
  2. 攻击者构造携带目标网站请求的恶意页面
  3. 用户访问恶意页面时触发请求
攻击流程图解
1. 用户登录银行网站A,获取认证Cookie → [用户浏览器] + [网站A Cookie]
2. 攻击者创建恶意网站B,内含隐藏的转账请求 → <img src="https://bankA/transfer?to=hacker&amt=1000">
3. 用户访问网站B时,浏览器自动向网站A发送请求并携带Cookie → 网站A误认为请求合法,执行转账
常见攻击场景
  • 自动提交表单:恶意页面通过<form>标签自动提交到目标网站
  • 图片/链接诱导:伪装成图片的请求(如<img src="...">
  • 钓鱼邮件:诱导用户点击含恶意请求的链接

三、CSRF 攻击的危害

  1. 账户安全:资金盗窃、信息篡改(如修改用户资料、绑定恶意账号)
  2. 数据泄露:诱导用户发送敏感信息请求(如获取订单列表)
  3. 业务破坏:批量执行恶意操作(如刷票、恶意注册)

四、防御方案(多层防护体系)

方案一:同源策略强化(基础防护)

原理:限制非同源请求的执行,但浏览器默认同源策略对 GET 请求限制较弱。
实现

  • 后端验证请求来源的 OriginReferer 头部
  • 仅允许白名单域名的请求(需注意跨域场景)
# 示例:Django 中验证 Referer(伪代码)
def transfer(request):
referer = request.META.get('HTTP_REFERER', '')
if not referer.startswith('https://yourbank.com'):
return HttpResponseForbidden("非法请求")
方案二:CSRF Token 机制(核心防护)

原理:在请求中加入随机令牌,后端验证令牌合法性。
实现步骤

  1. 服务器生成随机 Token 并存储(如 Session 或 Cookie)
  2. 页面表单或请求中携带 Token(如隐藏表单字段或请求头)
  3. 后端验证请求中的 Token 与存储的一致性
<!-- 前端表单携带 Token -->
<form action="/transfer" method="post">
<input type="hidden" name="csrf_token" value="随机令牌">
<input type="text" name="amount">
<button type="submit">转账</button>
</form>
// 后端验证示例(Spring Security)
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
}
方案三:SameSite Cookie(现代浏览器方案)

原理:通过 Cookie 的 SameSite 属性限制跨站请求携带 Cookie。
属性值

  • Strict:完全禁止跨站请求携带 Cookie
  • Lax:允许部分安全的跨站请求(如 GET 方法、顶级导航)
  • None:允许跨站请求(需配合 Secure 属性启用 HTTPS)
Set-Cookie: session_id=12345; SameSite=Lax; Secure; HttpOnly

原理:结合 Cookie 和请求参数中的 Token,利用浏览器跨站无法修改 Cookie 的特性。
实现

  1. 服务器在 Cookie 中存储 Token(如 X-CSRF-TOKEN
  2. 请求头或参数中携带相同 Token
  3. 后端验证 Cookie 与请求中的 Token 一致性
// 前端自动获取 Cookie 并添加到请求头
fetch('/api/action', {
method: 'POST',
headers: {
'X-CSRF-Token': document.cookie.match(/X-CSRF-TOKEN=([^;]+)/)[1]
}
})

五、各防御方案对比

方案核心原理优点缺点兼容性
同源策略验证验证请求来源域名实现简单依赖浏览器,可被伪造 Referer全兼容
CSRF Token随机令牌双向验证防护全面,兼容性好需前端后端配合全兼容
SameSite Cookie限制跨站 Cookie 携带浏览器原生支持,无额外开销iOS 12 以下、老版本浏览器不支持现代浏览器
双重 Cookie 验证结合 Cookie 和请求 Token无需服务器存储状态需 JavaScript 支持现代浏览器

六、实战优化建议

  1. 分级防护

    • 核心功能(如转账、修改密码)必须同时启用 Token 和 SameSite Cookie
    • 普通功能可仅用 Token 或 SameSite=Lax
  2. 防御绕过攻击

    • 禁止 GET 请求执行敏感操作(如删除数据)
    • 对敏感操作添加二次验证(如短信验证码)
  3. 框架集成

    • Spring Security、Django、Ruby on Rails 等框架内置 CSRF 防护,需正确配置
    • 前端框架(如 Vue、React)可通过插件自动注入 Token

七、总结:CSRF 防御最佳实践

  1. 必选方案:CSRF Token + SameSite=Lax Cookie
  2. 增强方案:双重 Cookie 验证 + 敏感操作二次验证
  3. 开发规范
    • 避免在 URL 中携带敏感参数(如 ?action=delete
    • 区分 GET(查询)和 POST/PUT/DELETE(修改)请求语义
    • 定期更新 Token 生成算法和密钥

通过多层防护体系,可有效抵御 99% 以上的 CSRF 攻击,同时保证用户体验不受影响。